package com.example.android.BluetoothChat;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.TimeChart;
import org.achartengine.model.TimeSeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class Main extends Activity {
	// Debugging
	private static final String TAG = "BluetoothChat";
	private static final boolean D = true;

	// Message types sent from the BluetoothChatService Handler
	public static final int MESSAGE_STATE_CHANGE = 1;
	public static final int MESSAGE_READ = 2;
	public static final int MESSAGE_WRITE = 3;
	public static final int MESSAGE_DEVICE_NAME = 4;
	public static final int MESSAGE_TOAST = 5;

	// Key names received from the BluetoothChatService Handler
	public static final String DEVICE_NAME = "device_name";
	public static final String TOAST = "toast";

	// Intent request codes
	private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
	private static final int REQUEST_ENABLE_BT = 3;
	// range means how many data can be received
	private static int range = 200;
	// key means how many data had been received
	private static int key = 0;
	// Array to store the data
	private static Double[] dataArrayList = new Double[range];
	// Buffer to store the received text
	StringBuilder sBuilder = new StringBuilder();

	// Name of the connected device
	private String mConnectedDeviceName = null;
	// Array adapter for the conversation thread
	private ArrayAdapter<String> mConversationArrayAdapter;
	// Local Bluetooth adapter
	private BluetoothAdapter mBluetoothAdapter = null;
	// Member object for the chat services
	private BluetoothChatService mChatService = null;
	// String buffer for outgoing messages
	private StringBuffer mOutStringBuffer;

	private TextView realTimeDataDisplay;
	private Button testButton;
	private TextView rDec;
	private String requestToSendRealtime = "2";

	DecimalFormat twoDForm = new DecimalFormat("#.##");
	SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
	int packetMaximumlength;
	String packdatabuffer = "";

	// The following is work for package data mode
	// private ProgressDialog progressDialog;
	// private String requestToSendPatch = "1";
	// private String requestToStart = "0";
	// private String requestASK = "F";
	static int getKey() {
		return key % range;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (D)
			Log.e(TAG, "+++ ON CREATE +++");

		setContentView(R.layout.main);

		// Get local Bluetooth adapter
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

		// If the adapter is null, then Bluetooth is not supported
		if (mBluetoothAdapter == null) {
			Toast.makeText(this, "Bluetooth is not available",
					Toast.LENGTH_LONG).show();
			finish();
			return;
		}
		testButton = (Button) findViewById(R.id.testButton);
		testButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				Random r = new Random();
				int rnd = r.nextInt(100) + 4;
				JsonHelper jh = new JsonHelper();
				Power pw = new Power();
				pw.setPower(Integer.toString(rnd));
				jh.postSingleDataToServer(WebserverURL.getUrl() + "data/send",
						pw);
			}
		});

		realTimeDataDisplay = (TextView) findViewById(R.id.realTimeDataDisplay);
		rDec = (TextView) findViewById(R.id.rDec);
		resetGraph();
	}

	private void resetGraph() {
		dataArrayInitialize(dataArrayList, 0, 0);
		setupGraph();
	}

	private void dataArrayInitialize(Double[] array, int increment,
			double startAt) {
		for (int j = 0; j < array.length; j++) {
			array[j] = startAt + increment * j;
		}
	}

	@Override
	public void onStart() {
		super.onStart();
		if (D)
			Log.e(TAG, "++ ON START ++");
		// If BT is not on, request that it be enabled.
		// setupChat() will then be called during onActivityResult
		if (!mBluetoothAdapter.isEnabled()) {
			Intent enableIntent = new Intent(
					BluetoothAdapter.ACTION_REQUEST_ENABLE);
			startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
			// Otherwise, setup the chat session
		} else {
			if (mChatService == null)
				setupChat();
		}
	}

	private void setupGraph() {
		GraphicalView mChartView;
		TimeSeries series = new TimeSeries("Power");
		fillData(series);
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
		dataset.addSeries(series);
		XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
		mRenderer.setYAxisMax(3.3);
		mRenderer.setYAxisMin(0.0);
		mRenderer.setLabelsTextSize(30);
		XYSeriesRenderer renderer = new XYSeriesRenderer();
		renderer.setColor(Color.GREEN); // set color
		mRenderer.addSeriesRenderer(renderer);
		LinearLayout layout = (LinearLayout) findViewById(R.id.chart);
		mChartView = ChartFactory.getTimeChartView(this, dataset, mRenderer,
				"H:mm");
		layout.removeAllViews();
		layout.addView(mChartView);
	}

	private void fillData(TimeSeries time_series) {
		Calendar cal = Calendar.getInstance();
		Date datetime_X = PacketData.addNSecond(cal.getTime(), -range);
		for (int i = 0; i < range; i++) {
			time_series.add(datetime_X, dataArrayList[(getKey() + i) % range]);
			datetime_X = PacketData.addNSecond(datetime_X, 1);
		}
	}

	@Override
	public synchronized void onResume() {
		super.onResume();
		if (D)
			Log.e(TAG, "+ ON RESUME +");

		// Performing this check in onResume() covers the case in which BT was
		// not enabled during onStart(), so we were paused to enable it...
		// onResume() will be called when ACTION_REQUEST_ENABLE activity
		// returns.
		if (mChatService != null) {
			// Only if the state is STATE_NONE, do we know that we haven't
			// started already
			if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
				// Start the Bluetooth chat services
				mChatService.start();
			}
		}
	}

	private void setupChat() {
		Log.d(TAG, "setupChat()");

		// Initialize the array adapter for the conversation thread
		mConversationArrayAdapter = new ArrayAdapter<String>(this,
				R.layout.message);

		// Initialize the BluetoothChatService to perform bluetooth connections
		mChatService = new BluetoothChatService(this, mHandler);

		// Initialize the buffer for outgoing messages
		mOutStringBuffer = new StringBuffer("");
	}

	public void sendMessage(String message) {
		// Check that we're actually connected before trying anything
		if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
			Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
					.show();
			return;
		}

		// Check that there's actually something to send
		if (message.length() > 0) {
			// Get the message bytes and tell the BluetoothChatService to write
			byte[] send = stringToBytesASCII(message);
			mChatService.write(send);
			// Reset out string buffer to zero and clear the edit text field
			mOutStringBuffer.setLength(0);
		}
	}

	@Override
	public synchronized void onPause() {
		super.onPause();
		if (D)
			Log.e(TAG, "- ON PAUSE -");
	}

	@Override
	public void onStop() {
		super.onStop();
		if (D)
			Log.e(TAG, "-- ON STOP --");
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		// Stop the Bluetooth chat services
		if (mChatService != null)
			mChatService.stop();
		if (D)
			Log.e(TAG, "--- ON DESTROY ---");
	}

	// The Handler that gets information back from the BluetoothChatService
	private final Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case MESSAGE_READ:
				byte[] readBuf = (byte[]) msg.obj;
				// construct a string from the valid bytes in the buffer
				String readMessage = new String(readBuf, 0, msg.arg1);

				mConversationArrayAdapter.add(readMessage);
				switch (ModeNow.getMode()) {
				// The following is work for package data mode
				// case Uploaddata:
				// packdatabuffer += readMessage;
				// // COMPLETE Data packet example:
				// // AC@AC@09@77@36@AC@AC@09@77@36@
				// packetMaximumlength = PacketData.powerListSize
				// * (PacketData.dataSize + PacketData.endBits
				// .length());
				// if (packdatabuffer.length() == packetMaximumlength) {
				// workWithUploadDataMode(packdatabuffer);
				// }
				// break;
				case Realtime:
					workWithRealtimeMode(readMessage);
					break;
				default:
					break;
				}
				break;
			case MESSAGE_DEVICE_NAME:
				// save the connected device's name
				mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
				Toast.makeText(getApplicationContext(),
						"Connected to " + mConnectedDeviceName,
						Toast.LENGTH_SHORT).show();
				break;
			case MESSAGE_TOAST:
				Toast.makeText(getApplicationContext(),
						msg.getData().getString(TOAST), Toast.LENGTH_SHORT)
						.show();
				break;
			}
		}

	};

	// The following is work for package data mode
	// private void workWithUploadDataMode(String readMessage) {
	// PacketData pd = new PacketData(readMessage);
	// if (pd.getResult() == "Success") {
	// progressDialog = ProgressDialog.show(Main.this, "Upload",
	// "Uploading, please wait...");
	// JsonHelper jh = new JsonHelper();
	// jh.postListDataToServer(WebserverURL.getUrl() + "data/insert",
	// pd.getPowerList());
	// progressDialog.dismiss();
	// sendMessage(this.requestASK);
	// } else {
	// Toast.makeText(getApplicationContext(), pd.getResult(),
	// Toast.LENGTH_SHORT).show();
	// }
	// packdatabuffer = "";
	// }

	private void workWithRealtimeMode(String readMessage) {
		// Data packet example:
		// DFAC@DFAC@EF09@DF77@CF36@DFAC@......
		int maxData = 65535;
		int minData = 0;
		for (int i = 0; i < readMessage.length(); i++) {
			if (readMessage.charAt(i) != '@') {
				if (CheckHex.isHexDigit(readMessage.charAt(i))) {
					sBuilder.append(readMessage.charAt(i));
				}
			} else if (readMessage.charAt(i) == '@') {
				if (sBuilder.length() > 0
						&& sBuilder.length() == PacketData.dataSize) {
					String hexString = sBuilder.toString();
					Double decimal = LookupTable.hexStringToDouble(hexString);
					if (decimal <= maxData && decimal >= minData) {
						try {
							String powerData = LookupTable.lookup(hexString);
							Double power = Double.valueOf(powerData);
							rDec.setText("Received current : "
									+ twoDForm.format(power / 220 * 1000) + "A");
							dataArrayList[getKey()] = power;
							JsonHelper jh = new JsonHelper();
							Power pw = new Power();
							pw.setPower(powerData);
							jh.postSingleDataToServer(WebserverURL.getUrl()
									+ "data/send", pw);
							realTimeDataDisplay.setText(dataArrayList[getKey()]
									.toString() + "kW");
						} catch (NumberFormatException e) {
							Toast.makeText(getApplicationContext(),
									dataArrayList[getKey()].toString(),
									Toast.LENGTH_SHORT).show();
						}
						key++;
						setupGraph();
					}
				}
				sBuilder.delete(0, sBuilder.length());
			}
		}
	}

	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (D)
			Log.d(TAG, "onActivityResult " + resultCode);
		switch (requestCode) {
		case REQUEST_CONNECT_DEVICE_SECURE:
			// When DeviceListActivity returns with a device to connect
			if (resultCode == Activity.RESULT_OK) {
				connectDevice(data, true);
			}
			break;
		case REQUEST_ENABLE_BT:
			// When the request to enable Bluetooth returns
			if (resultCode == Activity.RESULT_OK) {
				// Bluetooth is now enabled, so set up a chat session
				setupChat();
			} else {
				// User did not enable Bluetooth or an error occured
				Log.d(TAG, "BT not enabled");
				Toast.makeText(this, R.string.bt_not_enabled_leaving,
						Toast.LENGTH_SHORT).show();
				finish();
			}
		}
	}

	private void connectDevice(Intent data, boolean secure) {
		// Get the device MAC address
		String address = data.getExtras().getString(
				DeviceListActivity.EXTRA_DEVICE_ADDRESS);
		// Get the BLuetoothDevice object
		BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
		// Attempt to connect to the device
		mChatService.connect(device, secure);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.option_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Intent serverIntent = null;
		switch (item.getItemId()) {
		case R.id.secure_connect_scan:
			// Launch the DeviceListActivity to see devices and do scan
			serverIntent = new Intent(this, DeviceListActivity.class);
			startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
			return true;
			// case R.id.receive_patch_data:
			// resetGraph();
			// sendMessage(requestToSendPatch);
			// sBuilder.delete(0, sBuilder.length());
			// ModeNow.mode = ConnectionMode.Uploaddata;
			// return true;
		case R.id.receive_realtime_data:
			sendMessage(requestToSendRealtime);
			sBuilder.delete(0, sBuilder.length());
			packdatabuffer = "";
			ModeNow.mode = ConnectionMode.Realtime;
			return true;
		}
		return false;
	}

	public static byte[] stringToBytesASCII(String str) {
		char[] buffer = str.toCharArray();
		byte[] b = new byte[buffer.length];
		for (int i = 0; i < b.length; i++) {
			b[i] = (byte) buffer[i];
		}
		return b;
	}

}
